package com.vvv.designpattern.synchronizedpattern;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

/**
 * @author vvv
 * @date 2023-10-15 15 28
 * discription
 */
public class GuardedSuspensionWithFutures {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new Resident().start();
        }
        Thread.sleep(1000);
        for (Long boxesId : MailBoxes.getBoxesIds()) {
            new Postman(boxesId, "mail" + boxesId).start();
        }
    }
}

/**
 * 居民
 */
class Resident extends Thread{
    @Override
    public void run() {
        Box box = MailBoxes.createBoxes();
        Thread thread = Thread.currentThread();
        System.out.println("居民" + thread.getId() + "在信箱" + box.getId() + "等待收信");
        Object o = box.get(2000);
        System.out.println("居民" + thread.getId() + "收到了信了" + o);
    }
}

/**
 * 邮递员
 */
class Postman extends Thread{
    private long id;
    private String mail;

    public Postman(long id, String mail) {
        this.id = id;
        this.mail = mail;
    }

    @Override
    public void run() {
        // 先知道去哪个箱子里面送邮件
        Box box = MailBoxes.getBoxById(id);
        // 送件
        Thread thread = Thread.currentThread();
        box.complete(mail);
        System.out.println("Postman" + thread.getId() + "成功把信送" +mail+ "到信箱" + id);
    }
}

/**
 * 居民楼下的邮箱柜，类似于蜂巢
 */
class MailBoxes {
    private static Map<Long, Box> boxes = new Hashtable<>();
    private static long id = 1;
    
    private static synchronized long generateId() {
        return id++;
    }
    
    public static Box createBoxes() {
        long id = generateId();
        Box box = new Box(id);
        boxes.put(id, box);
        return box;
    }

    public static Set<Long> getBoxesIds() {
        return boxes.keySet();
    }

    public static Box getBoxById(long id) {
        return boxes.get(id);
    }
}

/**
 * 蜂巢里面的一个小邮箱柜
 */
class Box {
    // 柜子id
    private Long id;
    // 柜子里面的信
    private Object mail;

    public Box(Long id) {
        this.id = id;
    }

    public long getId() {
        return id;
    }

    public Object get(long timeout) {
        synchronized (this) {
            // 开始时间
            long beginTime = System.currentTimeMillis(); // 15:00:00
            // 经历的时间
            long passedTime = 0;
            // while 循环防止被虚假唤醒
            while (mail == null) {
                // 剩余的等待时间
                long waitTime = timeout - passedTime; // 2s 1s
                if (waitTime <= 0) {
                    break;
                }
                try {
                    this.wait(waitTime); // 15:01 被虚假唤醒
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                // 经历的时间
                passedTime = System.currentTimeMillis() - beginTime; //15:00:01 1s
            }
            return mail;
        }
    }

    public void complete(Object mail) {
        synchronized (this) {
            this.mail = mail;
            this.notifyAll();
        }
    }

    @Override
    public String toString() {
        return "GuardedObject{" +
                "mail=" + mail +
                '}';
    }
}
